package com.gzsxy.esjy.decoder.impl;

import com.gzsxy.esjy.decoder.BaseMessageDecoder;

import com.gzsxy.esjy.request.ContentType;
import com.gzsxy.esjy.request.HttpServletRequest;
import com.gzsxy.esjy.request.MultipartHttpRequest;
import com.gzsxy.esjy.request.impl.BaseRequest;
import com.gzsxy.esjy.response.NettyHttpResponse;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.http.FullHttpResponse;
import io.netty.handler.codec.http.HttpContent;
import io.netty.handler.codec.http.HttpMethod;
import io.netty.handler.codec.http.LastHttpContent;
import io.netty.handler.codec.http.multipart.Attribute;
import io.netty.handler.codec.http.multipart.FileUpload;
import io.netty.handler.codec.http.multipart.HttpPostRequestDecoder;
import io.netty.handler.codec.http.multipart.InterfaceHttpData;
import io.netty.handler.codec.http.multipart.InterfaceHttpData.HttpDataType;

import java.io.IOException;
import java.util.List;

/**
 * http解码器 
 * @author zhangxiaolong
 * @date 2022/7/6 9:36
 */
public class HttpContentDecoder extends BaseMessageDecoder<HttpContent> {
	
	
	
	@Override
	protected void decode(ChannelHandlerContext ctx, HttpContent msg, List<Object> out) throws Exception {
		//这时拿到的是上一个解码HttpRequestDecoder中set的request请求类型
		HttpServletRequest request = request(ctx, null);
		if(request == null || ((BaseRequest)request).isEnd()) {
			out.add(new Integer(0)) ;
			return ;
		}
		BaseRequest base =((BaseRequest)request);
		try {
			//文件上传
			if(request instanceof MultipartHttpRequest) {
				MultipartHttpRequest upload = (MultipartHttpRequest) request ;
				// 接收一个新的请求体
				upload.getPostRequestDecoder().offer(msg) ;
				//如果当前消息为最后的内容
				if(msg instanceof LastHttpContent) {
					// 将内存中的数据序列化本地
					readHttpDataChunkByChunk(upload);
				}
				//在线预览图片等等
			}else if(request.getMethod() == HttpMethod.POST) {
				writeRequestBody(msg.content(),request);
			}
		   //处理最后报文
			if(msg instanceof LastHttpContent) {
				if(request.getMethod() == HttpMethod.POST && request.getContentType() != ContentType.MULTIPART_FORM_DATA) {
					String result = null ;
					ByteBuf content = base.getContent();
					result = content.toString(request.getCharset());
					// 读完就释放（避免内存泄露）
					content.release();
					base.setRequestBody(result);
				}
				base.end();
				out.add(request) ;
				return ;
			}
		}catch (Exception e) {
			log.error(e.getMessage(), e);
			base.end();
			FullHttpResponse doExceptionResponse = NettyHttpResponse.doExceptionResponse(e, request==null?"utf-8":request.getCharset().name());
			ctx.writeAndFlush(doExceptionResponse) ;
		}
	}
	
	/**
	 * 写入文件
	 * @param content
	 * @param request
	 */
	private void writeRequestBody(ByteBuf content, HttpServletRequest request) {
		BaseRequest base = ((BaseRequest)request);
		ByteBuf cont = base.getContent() ;
		if(cont == null) {
			//获取请求数据长度
			int length  = (int)request.getContentLength();
			//创建一个ByteBuf对象
			cont = Unpooled.buffer(length) ;
			base.setContent(cont);
		}
		cont.writeBytes(content) ;
//		content.release();
	}
	
	
	/**
	 * 解析文件上传大包 （主要是为了显示当前解析的过程，是否成功）
	 * @throws IOException
	 */
	private void readHttpDataChunkByChunk(MultipartHttpRequest upload) throws IOException {
		HttpPostRequestDecoder decoder = upload.getPostRequestDecoder();
		while (decoder.hasNext()) {
			InterfaceHttpData data = decoder.next();
			if (data != null) {
				//获取数据类型
				HttpDataType httpDataType = data.getHttpDataType();
				if (httpDataType == HttpDataType.FileUpload) {
					FileUpload fileUpload = (FileUpload) data;
					long length = fileUpload.getFile().length();
					log.info("得到文件名称={} 参数名称{}  -{}b - {}K -{}M",fileUpload.getFilename(),fileUpload.getName(),length,length/1024,length/(1024*1024));
					String name = fileUpload.getName();
					//赋值请求参数
					upload.addParam(name, fileUpload);
				} else if (httpDataType == HttpDataType.Attribute) {
					Attribute attribute = (Attribute) data;
					//赋值请求参数
					upload.addParam(attribute.getName(), attribute.getValue());
				}
			}

		}
	}
	

	
}
